﻿using System.Linq;
using Cms.Application.IO;
using Cms.Application.WebFramework.Views;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.RepositoryInterfaces;

namespace Cms.Application.WebFramework.Presenters
{
    public class MediaHandlerPresenter : BasePresenter
    {
        private readonly IMediaHandlerView _view;
        private User _user;
        private ICmsFileInfo _fileInfo;

        public IDiskAccess DiskAccess { get; set; }

        public MediaHandlerPresenter(IMediaHandlerView view)
            : this(view, new RepositoryFactory())
        {
            DiskAccess = new DiskAccess();
        }

        public MediaHandlerPresenter(IMediaHandlerView view, IRepositoryFactory repositoryFactory)
            : base(repositoryFactory)
        {
            _view = view;
        }

        public void ProcessFile()
        {
            if (HasAccess())
            {
                _fileInfo = DiskAccess.GetFileInfo(_view.PhysicalFilePath);
                if (_fileInfo.Exists)
                {
                    DetermineFileTypeAndPrepareResponse();
                    return;
                }
            }
            _view.SetStatusCode(401); // Access denied or file does not exist
        }

        private bool HasAccess()
        {
            if (OverrideAccessControl || _view.MediaFile == null || FileIsPublic)
            {
                return true;
            }
            _user = UserRepository.GetUser(_view.UserId);
            return _user != null && UserHasAccessToRequiredUserGroups;
        }

        private void DetermineFileTypeAndPrepareResponse()
        {
            switch (_view.MediaFile.Extension.ToLower())
            {
                case "gif": Gif(); break;
                case "jpg": Jpg(); break;
                case "png": Png(); break;
                case "pdf": Pdf(); break;
                case "xlsx": Xlsx(); break;
                case "docx": Docx(); break;
                case "pptx": Pptx(); break;
                case "xls": Xls(); break;
                case "doc": Doc(); break;
                case "ppt": Ppt(); break;
                case "mdb": Mdb(); break;
                case "swf": Swf(); break;
                case "mp3": Mp3(); break;
                case "zip": Zip(); break;
                case "xml": Xml(); break;
                case "css": Css(); break;
                case "js": Js(); break;
                case "ogg":
                    Ogg();
                    break;
            }
            _view.AddHeader("Content-Length", _fileInfo.Length.ToString());
            _view.WriteFileToResponse(_view.MediaFile.GetVirtualPath());
        }

        private bool OverrideAccessControl
        {
            get { return _view.AdministratorId > 0; }
        }

        private bool FileIsPublic
        {
            get { return _view.MediaFile.GetRequiredUserGroups().Count == 0; }
        }

        private bool UserHasAccessToRequiredUserGroups
        {
            get { return _user.Memberships.Any(membership => _view.MediaFile.GetRequiredUserGroups().Contains(membership.UserGroup) && membership.IsActive()); }
        }

        private void Gif()
        {
            _view.SetContentType("image/gif");
            _view.InsertOutputCacheEntry();
        }

        private void Jpg()
        {
            _view.SetContentType("image/jpeg");
            _view.InsertOutputCacheEntry();
        }

        private void Png()
        {
            _view.SetContentType("image/png");
            _view.InsertOutputCacheEntry();
        }

        private void Pdf()
        {
            _view.SetContentType("application/pdf");
        }

        private void Xlsx()
        {
            _view.SetContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Docx()
        {
            _view.SetContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Pptx()
        {
            _view.SetContentType("application/vnd.openxmlformats-officedocument.presentationml.presentation");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Xls()
        {
            _view.SetContentType("application/vnd.ms-excel");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Doc()
        {
            _view.SetContentType("application/msword");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Ppt()
        {
            _view.SetContentType("application/vnd.ms-powerpoint");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Mdb()
        {
            _view.SetContentType("application/x-msaccess");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Swf()
        {
            _view.SetContentType("application/x-shockwave-flash");
        }

        private void Mp3()
        {
            _view.SetContentType("audio/mpeg3");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Ogg()
        {
            _view.SetContentType("audio/ogg");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Zip()
        {
            _view.SetContentType("application/zip");
            _view.AddHeader("Content-Disposition", "inline; filename=" + _view.MediaFile.Name);
        }

        private void Xml()
        {
            _view.SetContentType("text/xml");
        }

        private void Css()
        {
            _view.SetContentType("text/css");
        }

        private void Js()
        {
            _view.SetContentType("text/javascript");
        }

    }
}